#include "ahupid.h"
#include "ahudata.h"
#include "ahutimer.h"
#include "datacpy.h"
#include <math.h>

/* NOTE: 当前文件的函数声明要放在ahupidfunc.h中，否则头文件有重复包含问题*/

extern ahu_dev_t *ahu_dev_hd;

/* 温度pid初始化 */
void pidinit_temp(ahu_dev_t *ahu_dev)
{
    data_type_u val;
    Pid_Direction dirct;

    /* 读取冬夏转换点位 */
    read_vp_byname(ahu_dev, "WS-EX", &val);

    /* 如果是过渡季就不做pid初始化 */
    if(val.i == Transition){
        ES_PRT_INFO(" AHU: dev_id[%s], Transitional season: no need to start Temperature-pid \n", ahu_dev->device_id);
        ahu_dev->pidset.flag_temp = false;
        ahu_dev->pidset.ws_ex_done = false;
        return;

    /* 冬季正方向 */
    }else if(val.i == Winter){
        dirct = PID_DIRECT;

    /* 夏季反方向 */
    }else if(val.i == Summer){
        dirct = PID_REVERSE;
    }

    ahupid_t *pid = &(ahu_dev->pidset.temp);

    /* 回风温度点位 */
    pid->in = get_double_ptr_by_name("RA-T", ahu_dev);
    /* 温度设定点点位 */
    pid->set = get_double_ptr_by_name("RM-TSP", ahu_dev);

    /* VLV_C/CV_C/HV_C (二通水阀，冷水阀，热水阀) 只能3选1，平台会配置好 */
    if( (pid->out = get_double_ptr_by_name("VLV-C", ahu_dev)) != NULL ){
        ES_PRT_INFO("AHU: dev_id[%s], Temperature pid-out uses <VLV-C> \n", ahu_dev->device_id);
    
    /* 夏季 */
    }else if(val.i == Summer){
        pid->out = get_double_ptr_by_name("CV-C", ahu_dev);
        ES_PRT_INFO("AHU: dev_id[%s], Temperature pid-out uses <CV-C> \n", ahu_dev->device_id);

    /* 冬季 */
    }else if(val.i == Winter){
    pid->out = get_double_ptr_by_name("HV-C", ahu_dev);
        ES_PRT_INFO("AHU: dev_id[%s], Temperature pid(in out set) is NULL \n", ahu_dev->device_id);
    }

    if(!pid->in || !pid->out || !pid->set){
        ahu_dev->pidset.flag_temp = false;
        return;
    }

    pid_init(&pid->pid, pid->in, pid->out, pid->set, PID_TEMP_P, PID_TEMP_I, PID_TEMP_D, 0.0, dirct);
    /* 自动模式 */
    pid_setMode(&pid->pid, PID_AUTOMATIC);
    /* 限制输出值的范围 */
	pid_setOutputLimits(&pid->pid, OAD_MIN, OAD_MAX);

    ahu_dev->pidset.flag_temp = true;
}

/* 湿度pid初始化 */
void pidinit_hmdt(ahu_dev_t *ahu_dev)
{
    ahupid_t *pid = &(ahu_dev->pidset.hmdt);

    /* 回风湿度 */
    pid->in = get_double_ptr_by_name("RA-H", ahu_dev);
    /* 湿度设定点 */
    pid->set = get_double_ptr_by_name("RM-HSP", ahu_dev);
    /* 湿度调节阀 */
    pid->out = get_double_ptr_by_name("HUM-TC", ahu_dev);

    /* 上述3个点位存在，才能pid */
    if(pid->in && pid->set && pid->out){

        ahu_dev->pidset.flag_hmdt = true;

        ES_PRT_INFO("AHU: dev_id[%s], Do init pid of humudity \n", ahu_dev->device_id);
        pid_init(&pid->pid, pid->in, pid->out, pid->set, PID_HMDT_P, PID_HMDT_I, PID_HMDT_D, 0.0, PID_DIRECT);
        
        /* 自动模式 */
	    pid_setMode(&pid->pid, PID_AUTOMATIC);

        /* 限制输出值的范围 */
	    pid_setOutputLimits(&pid->pid, OAD_MIN, OAD_MAX);

    }else{
        ahu_dev->pidset.flag_hmdt = false;
        ES_PRT_INFO("AHU: dev_id[%s], Don't init pid of humudity \n", ahu_dev->device_id);
    }
}

/* 湿度的pid控制函数 */
void ahu_hmdt_proc_pid(ahu_dev_t *ahu_dev)
{
    double *in, *out, *set;

    in = ahu_dev->pidset.hmdt.in;
    out = ahu_dev->pidset.hmdt.out;
    set = ahu_dev->pidset.hmdt.set;

    long *tv_sec = &ahu_dev->pidset.hmdt.itvl_sec;
    time_t t;
    time(&t);
    /* 每15s 计算一次pid */
    if((t - *tv_sec) > TMO_PID_INTERVAL){
        /* (设定湿度 - 回风湿度) 绝对值 > 1% 才进行控制 */
        if( fabs(*set - *in) > 1.0 ){
            pid_compute(&ahu_dev->pidset.hmdt.pid);
            ES_PRT_INFO("AHU: dev_id[%s], hmdt ctrl: pid out = %lf in = %lf set %lf \n", ahu_dev->device_id, *out, *in, *set);
        }

        /* 刷新计时 */
        *tv_sec = t;
    }
}

/* 开关型湿度阀控制函数 */
void ahu_hmdt_proc_sw(ahu_dev_t *ahu_dev)
{
    /* 读取湿度设定点value */
    data_type_u val_set;
    read_vp_byname(ahu_dev, "RM-HSP", &val_set);

    /* 读取回风湿度 */
    data_type_u val_ret;
    read_rp_byname(ahu_dev, "RA-H", &val_ret);

    /* 读取湿度调节阀 */
    data_type_u val_out;
    read_rp_byname(ahu_dev, "HUM-C", &val_out);

    /* 设定值>反馈值就开加湿阀 */
    if(val_set.d - val_ret.d > 1.0){
        /* 没开的话就打开 */
        if(val_out.b == false){
            val_out.b = true;
            /* 将点位发送出去 */
            set_cmdpoint_ifexist("HUM-C", ahu_dev, val_out, TypeOfVal_BOOL);
        }

    /* 关加湿阀 */
    }else{

        /* 没关的话就关 */
        if(val_out.b == true){
            val_out.b = false;
            /* 将点位发送出去 */
            set_cmdpoint_ifexist("HUM-C", ahu_dev, val_out, TypeOfVal_BOOL);
        }
    }
}

/* 湿控线程 */
void *ahu_hmdt_ctl_thread(void *arg)
{
    pthread_detach(pthread_self());

    ahu_dev_t *pos;

    while(1){
        sleep(2);

        /* 遍历每个设备 */
        list_for_each_entry(pos, &ahu_dev_hd->list, list){
            /* 每个空调在idle态才进行控制 */
            if(pos->fsm.cur_state == S_IDLE){
            
                /* true: pid控制 */
                if(pos->pidset.flag_hmdt == true){
                    ahu_hmdt_proc_pid(pos);


                /* 开关加湿阀控制 */
                }else if(is_point_exist(pos, "HUM-C") == true){
                    ahu_hmdt_proc_sw(pos);
                }
                
            }
        }

    }
    return NULL;
}

/* 温度pid控制函数 */
void ahu_temp_proc_pid(ahu_dev_t *ahu_dev)
{
    data_type_u val;
    double *in, *out, *set;

    in = ahu_dev->pidset.temp.in;
    out = ahu_dev->pidset.temp.out;
    set = ahu_dev->pidset.temp.set;

    long *tv_sec = &ahu_dev->pidset.temp.itvl_sec;
    time_t t;
    time(&t);
    /* 每15s 计算一次pid */
    if((t - *tv_sec) > TMO_PID_INTERVAL){

        /* (设定湿度 - 回风湿度) 绝对值 > 1% 才进行控制 */
        if( fabs(*set - *in) > 1.0 ){
            pid_compute(&ahu_dev->pidset.temp.pid);
            ES_PRT_INFO("AHU: dev_id[%s], temp ctrl: pid out = %lf in = %lf set %lf \n", ahu_dev->device_id, *out, *in, *set);
            
            val.d = *out;
            
            set_cmdpoint_ifexist("VLV-C", ahu_dev, val, TypeOfVal_DOUBLE);

            if(ahu_dev->pidset.season == Winter){
                set_cmdpoint_ifexist("CV-C", ahu_dev, val, TypeOfVal_DOUBLE);
            }else if(ahu_dev->pidset.season == Summer){
                set_cmdpoint_ifexist("HV-C", ahu_dev, val, TypeOfVal_DOUBLE);
            }

        }

        /* 刷新计时 */
        *tv_sec = t;
    }
}

/* 过渡季送风机运行时，新风阀全开，回风阀关闭，按最大新风比运行 */
void ahu_temp_proc_transition(ahu_dev_t *ahu_dev)
{
    if(ahu_dev->pidset.ws_ex_done == true){
        return;
    }

    data_type_u val;

    /* 1 新风阀 */
        /* 1.1 开关型 */
        val.b = true;
        set_cmdpoint_ifexist("OAD-C", ahu_dev, val, TypeOfVal_BOOL);

        /* 1.2 调节型 */
        val.d = 100.0;
        set_cmdpoint_ifexist("OAD-TC", ahu_dev, val, TypeOfVal_DOUBLE);

    /* 2. 回风阀 */
        /* 2.1 开关型 */
        val.b = false;
        set_cmdpoint_ifexist("RAD-C", ahu_dev, val, TypeOfVal_BOOL);

        /* 2.2 调节型 */
        val.d = 0.0;   // 新风阀+回风阀 = 100.0%
        set_cmdpoint_ifexist("RAD-TC", ahu_dev, val, TypeOfVal_DOUBLE);

    ahu_dev->pidset.ws_ex_done = true;
}

/* 温控线程 */
void *ahu_temp_ctl_thread(void *arg)
{
    pthread_detach(pthread_self());

    ahu_dev_t *pos;

    while(1){
        sleep(2);

        /* 遍历每个设备 */
        list_for_each_entry(pos, &ahu_dev_hd->list, list){

            /* 每个空调在idle态才进行控制 */
            if(pos->fsm.cur_state == S_IDLE){

                /* 如果季节变换，要重新pid init */
                if(pos->pidset.changed == CHANGED){
                    pidinit_temp(pos);
                    pos->pidset.changed = !CHANGED;
                }

                /* true: pid控制 */
                if(pos->pidset.flag_temp == true){
                    ahu_temp_proc_pid(pos);

                }else{
                    /* 过渡季处理方式 */
                    if(pos->pidset.season == Transition){
                        ahu_temp_proc_transition(pos);
                    }
                }
            }
        }
    }

    return NULL;
}